#pragma once

#include "Data.h"

//image_parse::CFeatureFactory_ImageParse::CParameters image_parse::CFeatureFactory_ImageParse::Parameters;

bool image_parse::CPixelSetTools::CLabeledPixel::Compare_byFileIndex(const CPixelSetTools::CLabeledPixel& a, const CPixelSetTools::CLabeledPixel& b)
{
	return (a.FileIndex < b.FileIndex);
}

bool image_parse::CPixelSetTools::CLabeledPixel::InputFromStream(istream& inStream)
{
	if (!(inStream>>FileIndex>>x>>y>>Label)) return false;
	return true;
}

void image_parse::CPixelSetTools::CLabeledPixel::OutputToStream(ostream& outStream) const
{
	outStream<<FileIndex<<"\t"<<x<<"\t"<<y<<"\t"<<Label<<endl;
}

int image_parse::CPixelSetTools::InputPixelListFromFile(CSimpleTypeArray<CLabeledPixel>& DstPixelList, string strFN_SrcData)
{
	int ret = 0;
	CLabeledPixel tPixel;

	ifstream inFile(strFN_SrcData.c_str());
	DstPixelList.Clear();
	while (tPixel.InputFromStream(inFile))
	{
		++ret;
		DstPixelList.PushBack(tPixel);
	}
	sort(DstPixelList.Begin(), DstPixelList.End(), &CLabeledPixel::Compare_byFileIndex);
	inFile.clear();
	inFile.close();
	return ret;
}

void image_parse::CPixelSetTools::OutputPixelListToFile(string strFN_DstData, const CSimpleTypeArray<CLabeledPixel>& SrcPixelList)
{
	int i;
	const CLabeledPixel* qp = SrcPixelList.pElement;
	ofstream outFile(strFN_DstData.c_str());
	for ( i = 0; i < (int)SrcPixelList.Size; ++i )
		(qp++)->OutputToStream(outFile);
	outFile.clear();
	outFile.close();
}

int image_parse::CPixelSetTools::GenerateFullPixelList(
	CSimpleTypeArray<CPixelSetTools::CLabeledPixel>& DstPixelList,
	const CFileEntity& FileEntity, int FileIndex,
	bool fClearBeforePushback)
{
	int i,j;

	if (fClearBeforePushback) DstPixelList.Clear();
	size_t z = DstPixelList.Size;
	DstPixelList.Resize(z + FileEntity.WH);
	CPixelSetTools::CLabeledPixel* pPixel = DstPixelList.pElement + z;
	const int* ql = FileEntity.LabelImage.data;
	for ( i = 0; i < FileEntity.H; ++i )
		for ( j = 0; j < FileEntity.W; ++j )
		{
			pPixel->x = j;
			pPixel->y = i;
			pPixel->FileIndex = FileIndex;
			(pPixel++)->Label = *(ql++);
		}
	return FileEntity.WH;
}

int image_parse::CPixelSetTools::GenerateRandomPixelList(
	CSimpleTypeArray<CPixelSetTools::CLabeledPixel>& DstPixelList,
	const CFileEntity& FileEntity, int FileIndex,
	int PixelMargin, double PixelSampleRate,
	bool fClearBeforePushback)
{
	if (PixelSampleRate<-EPS) PixelSampleRate = 1.0 + EPS;

	int ret = 0;
	int i,j,o,q,dx,dy,dx2,t,z;
	CPixelSetTools::CLabeledPixel tPixel;

	tPixel.FileIndex = FileIndex;

	if (fClearBeforePushback) DstPixelList.Clear();

	CSimpleTypeArray<int> q2map;
	CSimpleTypeArray<int> map2q;
	q2map.Clear(); q2map.Resize(FileEntity.WH); q2map.Resize(0);
	map2q.Clear(); map2q.Resize(FileEntity.WH, -1);

	for ( i = 0; i < FileEntity.H; ++i )
		for ( j = 0; j < FileEntity.W; ++j )
		{
			t = j + i * FileEntity.W;
			map2q.pElement[t] = (int)q2map.Size; q2map.PushBack(t);
		}

	for ( z = (int)q2map.Size; z > 0; )
	{
		i = CMyRandom::NextInt(z);
		t = q2map.pElement[i];

		tPixel.x = t % FileEntity.W;
		tPixel.y = t / FileEntity.W;
		tPixel.Label = FileEntity.LabelImage.data[t];
		if (CMyRandom::NextDouble() < PixelSampleRate)
		{
			++ret;
			DstPixelList.PushBack(tPixel);
		}

		if (tPixel.Label == 0)				// by yhchen
		{
			for ( dy = -PixelMargin; dy <= +PixelMargin; ++dy)
			{
				dx2 = PixelMargin - abs(dy);
				for ( dx = -dx2; dx <= +dx2; ++dx)
				{
					o = tPixel.x + dx; if (o<0 || o>=FileEntity.W) continue;
					j = tPixel.y + dy; if (j<0 || j>=FileEntity.H) continue;

					o = t + dx + dy * FileEntity.W;
					j = map2q.pElement[o]; if (j < 0) continue;

					if (FileEntity.LabelImage.data[o] != tPixel.Label)				// by yhchen
					{
						continue;
					}

					q = q2map.pElement[--z];
					q2map.pElement[j] = q; map2q.pElement[q] = j;
					//q2map.pElement[z] = o; map2q.pElement[o] = z;

					map2q.pElement[o] = -1;
					q2map.PopBack();
				}
			}
		}
		else
		{
			o	= t;
			j	= map2q.pElement[o];
			q	= q2map.pElement[--z];

			q2map.pElement[j] = q;
			map2q.pElement[q] = j;

			map2q.pElement[o] = -1;
			q2map.PopBack();
		}
	}

	return ret;
}

//void image_parse::CFeatureFactory_ImageParse::BuildFilterSet(CImageFilterSet& DstIFS)
//{
//	DstIFS.Clear();
//	DstIFS.PushBack(new CImageFilter_ColorChannel(0));
//	DstIFS.PushBack(new CImageFilter_ColorChannel(1));
//	DstIFS.PushBack(new CImageFilter_ColorChannel(2));
//	DstIFS.PushBack(new CImageFilter_ColorChannel(3));
//	DstIFS.PushBack(new CImageFilter_Gaussian(3, Parameters.TextonSigma * 1.0));
//	DstIFS.PushBack(new CImageFilter_Gaussian(3, Parameters.TextonSigma * 2.0));
//	DstIFS.PushBack(new CImageFilter_Gaussian(3, Parameters.TextonSigma * 4.0));
//	DstIFS.PushBack(new CImageFilter_Gaussian(4, Parameters.TextonSigma * 1.0));
//	DstIFS.PushBack(new CImageFilter_Gaussian(4, Parameters.TextonSigma * 2.0));
//	DstIFS.PushBack(new CImageFilter_Gaussian(4, Parameters.TextonSigma * 4.0));
//	DstIFS.PushBack(new CImageFilter_Gaussian(5, Parameters.TextonSigma * 1.0));
//	DstIFS.PushBack(new CImageFilter_Gaussian(5, Parameters.TextonSigma * 2.0));
//	DstIFS.PushBack(new CImageFilter_Gaussian(5, Parameters.TextonSigma * 4.0));
//	DstIFS.PushBack(new CImageFilter_LoG(3, Parameters.TextonSigma * 1.0));
//	DstIFS.PushBack(new CImageFilter_LoG(3, Parameters.TextonSigma * 2.0));
//	DstIFS.PushBack(new CImageFilter_LoG(3, Parameters.TextonSigma * 4.0));
//	DstIFS.PushBack(new CImageFilter_LoG(3, Parameters.TextonSigma * 8.0));
//	DstIFS.PushBack(new CImageFilter_1DoG(3, Parameters.TextonSigma * 2.0, true));
//	DstIFS.PushBack(new CImageFilter_1DoG(3, Parameters.TextonSigma * 4.0, true));
//	DstIFS.PushBack(new CImageFilter_1DoG(3, Parameters.TextonSigma * 2.0, false));
//	DstIFS.PushBack(new CImageFilter_1DoG(3, Parameters.TextonSigma * 4.0, false));
//
//	DstIFS.PushBack(new CImageFilter_DooG(3, 1.0, 0.0*PI/6, 3.0));
//	DstIFS.PushBack(new CImageFilter_DooG(3, 1.0, 1.0*PI/6, 3.0));
//	DstIFS.PushBack(new CImageFilter_DooG(3, 1.0, 2.0*PI/6, 3.0));
//	DstIFS.PushBack(new CImageFilter_DooG(3, 1.0, 3.0*PI/6, 3.0));
//	DstIFS.PushBack(new CImageFilter_DooG(3, 1.0, 4.0*PI/6, 3.0));
//	DstIFS.PushBack(new CImageFilter_DooG(3, 1.0, 5.0*PI/6, 3.0));
//	DstIFS.PushBack(new CImageFilter_DooG(3, 1.8, 0.0*PI/6, 3.0));
//	DstIFS.PushBack(new CImageFilter_DooG(3, 1.8, 1.0*PI/6, 3.0));
//	DstIFS.PushBack(new CImageFilter_DooG(3, 1.8, 2.0*PI/6, 3.0));
//	DstIFS.PushBack(new CImageFilter_DooG(3, 1.8, 3.0*PI/6, 3.0));
//	DstIFS.PushBack(new CImageFilter_DooG(3, 1.8, 4.0*PI/6, 3.0));
//	DstIFS.PushBack(new CImageFilter_DooG(3, 1.8, 5.0*PI/6, 3.0));
//
//	DstIFS.PushBack(new CImageFilter_DoG(3, 1.0));
//	DstIFS.PushBack(new CImageFilter_DoG(3, 1.5));
//	DstIFS.PushBack(new CImageFilter_DoG(3, 3.0));
//	DstIFS.PushBack(new CImageFilter_DoG(3, 4.0));
//
//	DstIFS.PushBack(new CImageFilter_CannyEdge(3, 1.0, 0.334, 0.667, 0.0, (PI+PI)/1));
//	DstIFS.PushBack(new CImageFilter_CannyEdge(3, 1.0, 0.334, 0.667, 0*PI/4, (PI+PI)/4));
//	DstIFS.PushBack(new CImageFilter_CannyEdge(3, 1.0, 0.334, 0.667, 1*PI/4, (PI+PI)/4));
//	DstIFS.PushBack(new CImageFilter_CannyEdge(3, 1.0, 0.334, 0.667, 2*PI/4, (PI+PI)/4));
//	DstIFS.PushBack(new CImageFilter_CannyEdge(3, 1.0, 0.334, 0.667, 3*PI/4, (PI+PI)/4));
//
//	DstIFS.PushBack(new CImageFilter_CannyEdge(3, 1.5, 0.500, 0.833, 0.0, (PI+PI)/1));
//	DstIFS.PushBack(new CImageFilter_CannyEdge(3, 1.5, 0.500, 0.833, 0*PI/4, (PI+PI)/4));
//	DstIFS.PushBack(new CImageFilter_CannyEdge(3, 1.5, 0.500, 0.833, 1*PI/4, (PI+PI)/4));
//	DstIFS.PushBack(new CImageFilter_CannyEdge(3, 1.5, 0.500, 0.833, 2*PI/4, (PI+PI)/4));
//	DstIFS.PushBack(new CImageFilter_CannyEdge(3, 1.5, 0.500, 0.833, 3*PI/4, (PI+PI)/4));
//}
//
//bool image_parse::CPattern::InputFromStream(istream& inStream)
//{
//	if (!(inStream>>xL>>yL>>xH>>yH)) return false;
//	//if (!(inStream>>xL>>yL>>xH>>yH>>Mode)) return false;
//	return true;
//}
//
//void image_parse::CPattern::OutputToStream(ostream& outStream) const
//{
//	outStream<<xL<<"\t"<<yL<<"\t"<<xH<<"\t"<<yH;//<<"\t"<<Mode;
//	outStream<<endl;
//}
//
//void image_parse::CPatternSet::myInit(string strFN_PatternConfiguration)
//{
//	int i,j,o,n;
//	CSimpleTypeArray<int> ScaleList;
//	CPattern tPattern, ttPattern;
//
//	ifstream inFile(strFN_PatternConfiguration.c_str());
//
//	PatternList.Clear();
//	for (;;)
//	{
//		if (!(inFile>>j)) break;
//		ScaleList.Resize(j);
//		for ( i = 0; i < ScaleList.Size; ++i )
//			inFile>>ScaleList.pElement[i];
//		inFile>>n;
//		for ( i = 0; i < n; ++i )
//		{
//			tPattern.InputFromStream(inFile);
//			for ( j = 0; j < ScaleList.Size; ++j )
//			{
//				o = ScaleList.pElement[j];
//				ttPattern.xL = tPattern.xL * o + o / 2;
//				ttPattern.xH = tPattern.xH * o + o / 2;
//				ttPattern.yL = tPattern.yL * o + o / 2;
//				ttPattern.yH = tPattern.yH * o + o / 2;
//				//ttPattern.Mode = tPattern.Mode;
//				PatternList.PushBack(ttPattern);
//			}
//		}
//	}
//
//	inFile.clear();
//	inFile.close();
//}
//
//void image_parse::CSingleResponseDescriptor::SetPatternSet(const CPatternSet* pPatternSet)
//{
//	_pPatternSet = pPatternSet;
//	PatternAmount = (int)_pPatternSet->PatternList.Size;
//	Size = PatternAmount * 2;
//}
//
//void image_parse::CSingleResponseDescriptor::SetSource(const double* SrcResponce, int W, int H)
//{
//	imvComputer.myInit(SrcResponce, W, H);
//}
//
//void image_parse::CSingleResponseDescriptor::ComputeDescriptor(double* DstData, int x, int y)
//{
//	int i;
//	double* p1 = DstData;
//	double* p2 = DstData + 1;
//	const CPattern* qPattern = _pPatternSet->PatternList.pElement;
//	for ( i = 0; i < PatternAmount; ++i, p1+=2, p2+=2, ++qPattern )
//		imvComputer.CalcRectangle(
//			*p1, *p2,
//			x + qPattern->xL, y + qPattern->yL,
//			x + qPattern->xH, y + qPattern->yH
//			);
//}

//void image_parse::CImagePixelFeatureExtractor_ImageParse::myInit()
//{
//	int i;
//
//	CFeatureFactory_ImageParse::BuildFilterSet(_IFS);
//	_ImageExtent = CFeatureFactory_ImageParse::Parameters.ImageExtent;
//
//	SRD_List.Resize(_IFS.FilterAmount);
//	SRD_Start.Clear(); SRD_Start.PushBack(0);
//	SRD_Sign.Resize(_IFS.FilterAmount);
//	FeatureDim = 0;
//	for ( i = 0; i < _IFS.FilterAmount; ++i )
//	{
//		SRD_List.pElement[i].SetPatternSet(&CFeatureFactory_ImageParse::Parameters.PatternList);
//		FeatureDim += SRD_List.pElement[i].Size;
//		SRD_Start.PushBack(FeatureDim);
//	}
//	CacheSign.Resize(FeatureDim);
//	CacheData.Resize(FeatureDim); CacheData.Fill(0.0);
//
//	ClearSRD();
//	ClearCache();
//}
//
//void image_parse::CImagePixelFeatureExtractor_ImageParse::SetImage(string strFN_Image)
//{
//	CImg<int> imgTemp;
//	CExternalTools::myLoadImage(strFN_Image, imgTemp);
//	SetImage(imgTemp);
//}
//
//void image_parse::CImagePixelFeatureExtractor_ImageParse::SetImage(const CImg<int> SourceRGBImage)
//{
//	CImg<int> imgTemp;
//	CRichImage SourceRichImage;
//	CExternalTools::EnlargeImage(imgTemp, SourceRGBImage, _ImageExtent, _ImageExtent);
//	SourceRichImage.LoadImage(imgTemp);
//	_IFS.WorkOnImage(SourceRichImage);
//
//	ClearSRD();
//	ClearCache();
//}
//
//void image_parse::CImagePixelFeatureExtractor_ImageParse::ClearSRD()
//{
//	SRD_Sign.Fill(false);
//}
//
//void image_parse::CImagePixelFeatureExtractor_ImageParse::ClearCache()
//{
//	CacheSign.Fill(false);
//	TargetX = TargetY = -1;
//}
//
//void image_parse::CImagePixelFeatureExtractor_ImageParse::SetTargetPixel(int x, int y)
//{
//	if (x!=TargetX || y!=TargetY)
//	{
//		ClearCache();
//		TargetX = x; TargetY = y;
//	}
//}
//
//double image_parse::CImagePixelFeatureExtractor_ImageParse::GetFeature(int x, int y, int FeatureIndex)
//{
//	SetTargetPixel(x, y);
//	return GetFeature(FeatureIndex);
//}
//
//int image_parse::CImagePixelFeatureExtractor_ImageParse::GetFeatureDim()
//{
//	return FeatureDim;
//}
//
//double image_parse::CImagePixelFeatureExtractor_ImageParse::GetFeature(int FeatureIndex)
//{
//	if (FeatureIndex<0 || FeatureIndex>=FeatureDim) return 0.0;
//
//	double ret;
//	int i,j;
//
//	if (!CacheSign.pElement[FeatureIndex])
//	{
//		i = (int)(upper_bound(SRD_Start.Begin(), SRD_Start.End(), FeatureIndex) - SRD_Start.Begin() - 1);
//		CSingleResponseDescriptor& SRD_i = SRD_List.pElement[i];
//		int iStart = SRD_Start.pElement[i];
//		int iEnd = SRD_Start.pElement[i+1];
//		if (!SRD_Sign.pElement[i])
//		{
//			SRD_Sign.pElement[i] = true;
//			SRD_i.SetSource(_IFS.GetFilterResponse(i), _IFS.W, _IFS.H);
//		}
//		SRD_i.ComputeDescriptor(CacheData.pElement + iStart, TargetX + _ImageExtent, TargetY + _ImageExtent);
//		for ( j = iStart; j < iEnd; ++j )
//			CacheSign.pElement[j] = true;
//	}
//
//	ret = CacheData.pElement[FeatureIndex];
//
//	return ret;
//}

void image_parse::CDataSet_ImageParse_ByImage::InitIPFE(CImageFilterBank* pFixIFB)
//void image_parse::CDataSet_ImageParse_ByImage::InitIPFE(const CTempTRSsetting* pFixed_trs_setting)
{
	if (_pIPFE == NULL)
		_pIPFE = CFeatureFactory_ImageParse::GenerateIPFE(pFixIFB);
		//_pIPFE = C_IPFE_Factory_ImageParse::GenerateIPFE();

	_LastFileIndex = -1;

	//_p_trs_setting = pFixed_trs_setting;
}

void image_parse::CDataSet_ImageParse_ByImage::InitPixelList(string strFN_PixelList, string strFN_Pfx_ImageCacheHashName, const CFileList* pFileList, const CClassInfoSet* pClassSet)
{
	this->strFN_Pfx_ImageCacheHashName = strFN_Pfx_ImageCacheHashName;
	_pClassSet = pClassSet;
	_pFileList = pFileList;
	CPixelSetTools::InputPixelListFromFile(PixelList, strFN_PixelList);
	_LastFileIndex = -1;
}

int image_parse::CDataSet_ImageParse_ByImage::GetFeatureDimention()
{
	return _pIPFE->GetFeatureDimention();
	//return _IPFE.FeatureDim;
}

int image_parse::CDataSet_ImageParse_ByImage::GetNodeAmount()
{
	return (int)PixelList.Size;
}

int image_parse::CDataSet_ImageParse_ByImage::GetNodeLabel(int NodeIndex)
{
	if (NodeIndex<0 || NodeIndex>=(int)PixelList.Size) return -1;
	return PixelList.pElement[NodeIndex].Label;
}

double image_parse::CDataSet_ImageParse_ByImage::GetNodeInitialWeight(int NodeIndex)
{
	return 1.0;
}

double image_parse::CDataSet_ImageParse_ByImage::GetNodeFeature(int NodeIndex, int FeatureIndex)
{
	if (NodeIndex<0 || NodeIndex>=(int)PixelList.Size) return 0.0;
	if (FeatureIndex<0 || FeatureIndex>=_pIPFE->GetFeatureDimention()) return 0.0;
	double ret;

	CPixelSetTools::CLabeledPixel& tPixel = PixelList.pElement[NodeIndex];
	int qx, qy;

	if (tPixel.FileIndex != _LastFileIndex)
	{
		_LastFileIndex = tPixel.FileIndex;
		CImg<int> imgSrc;
		CExternalTools::myLoadImage(_pFileList->SourceImageList.pElement[_LastFileIndex], imgSrc);

		//if (_p_trs_setting!=NULL && _p_trs_setting->fDo)
		//{
		//	double nw, nh, sx, sy, ow, oh;
		//	ow = imgSrc.dimx(); oh = imgSrc.dimy();
		//	sx = _p_trs_setting->xScale;
		//	sy = _p_trs_setting->yScale;
		//	nw = ow * sx;
		//	nh = oh * sy;

		//	_trs_config.myInit(
		//		ow/2.0, oh/2.0,
		//		nw/2.0, nh/2.0,
		//		1.0, 1.0,
		//		_p_trs_setting->Angle, 0.0
		//		);

		//	C_TRSable_Image trsImage;
		//	trsImage.myInit(imgSrc);
		//	trsImage.BuildImage(imgSrc, (int)(nw+0.5), (int)(nh+0.5), _trs_config, _p_trs_setting->fTile);
		//}

		char strTemp[10001];
		sprintf_s(strTemp, "%s.%04d", strFN_Pfx_ImageCacheHashName.c_str(), _LastFileIndex);
		_pIPFE->SetImage(imgSrc, strTemp);
	}

	//if (_p_trs_setting!=NULL && _p_trs_setting->fDo)
	//{
	//	double ox, oy;
	//	_trs_config.ComputeNewPosition(ox, oy, tPixel.x+0.5, tPixel.y+0.5);
	//	qx = (int)ox;
	//	qy = (int)oy;
	//}
	//else
	{
		qx = tPixel.x;
		qy = tPixel.y;
	}

	ret = _pIPFE->GetFeature(qx, qy, FeatureIndex);

	return ret;
}

